package com.ark.cloud.dataservices.modules.sys.service.impl;

import com.ark.cloud.dataservices.common.exception.BaseException;
import com.ark.cloud.dataservices.common.exception.MobileExistException;
import com.ark.cloud.dataservices.common.exception.SystemErrorType;
import com.ark.cloud.dataservices.common.exception.UserNameExistException;
import com.ark.cloud.dataservices.common.exception.UserNotFoundException;
import com.ark.cloud.dataservices.common.utils.UserContextHolder;
import com.ark.cloud.dataservices.modules.sys.dao.UserMapper;
import com.ark.cloud.dataservices.modules.sys.entity.form.PassWordForm;
import com.ark.cloud.dataservices.modules.sys.entity.param.UserQueryParam;
import com.ark.cloud.dataservices.modules.sys.entity.po.Module;
import com.ark.cloud.dataservices.modules.sys.entity.po.Role;
import com.ark.cloud.dataservices.modules.sys.entity.po.User;
import com.ark.cloud.dataservices.modules.sys.entity.vo.CustomerUserDetails;
import com.ark.cloud.dataservices.modules.sys.entity.vo.UserVo;
import com.ark.cloud.dataservices.modules.sys.service.IRoleService;
import com.ark.cloud.dataservices.modules.sys.service.ISeatService;
import com.ark.cloud.dataservices.modules.sys.service.IUserRoleService;
import com.ark.cloud.dataservices.modules.sys.service.IUserService;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.HashSet;
import java.util.List;
import java.util.Objects;
import java.util.Set;

@Service
@Slf4j
public class UserService extends ServiceImpl<UserMapper, User> implements IUserService {

    private final IUserRoleService userRoleService;
    private final IRoleService roleService;
    private final ISeatService seatService;
    private final PasswordEncoder passwordEncoder;

    public UserService(IUserRoleService userRoleService, IRoleService roleService, ISeatService seatService,PasswordEncoder passwordEncoder) {
        this.userRoleService = userRoleService;
        this.roleService = roleService;
        this.seatService = seatService;
        this.passwordEncoder = passwordEncoder;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean add(User user) {
        if (StringUtils.isNotBlank(user.getPassword())) {
            user.setPassword(passwordEncoder.encode(user.getPassword()));
        }
        boolean inserts = false;
        try {
            inserts = this.save(user);
        } catch (DuplicateKeyException e) {
                String message = e.getCause().toString();
                if (StringUtils.isNotBlank(message)) {
                    if (message.contains("ux_users_username")) {
                        throw new UserNameExistException("user name exist with " + user.getUsername());
                    } else if (e.getCause().toString().contains("ux_users_mobile")) {
                        throw new MobileExistException("mobile exist with " + user.getMobile());
                    }
                }
        }
        userRoleService.saveBatch(user.getId(), user.getRoleIds());
        Set<String> groupIds = user.getGroupIds();
        if (CollectionUtils.isEmpty(groupIds)) {
            groupIds = new HashSet<>();
            groupIds.add("");
            user.setGroupIds(groupIds);
        }
        return inserts;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean delete(String id) {
        this.getBaseMapper().deleteUSRByUserId(id);
        this.removeById(id);
        return true;
    }

    @Override
    public boolean alterPassword(PassWordForm passWordForm) {
        String username = UserContextHolder.getInstance().getUsername();
        String password = passWordForm.getPassword();
        String newPassword = passWordForm.getNewPassword();
        User userBean = getByUniqueId(username);
        if (userBean == null) {
            throw new BaseException(SystemErrorType.ACCOUNT_INEXISTENCE);
        }
        if (!Objects.equals(password, userBean.getPassword())) {
            return false;
        }
//        if (!passwordEncoder.matches(password, userBean.getPassword())) {
//            return false;
//        }
        User user = new User();
        user.setId(userBean.getId());
        user.setPassword(newPassword);
        return update(user);
    }

    @Override
    public User queryUserInfo(String username) {
        return getByUniqueId(username);
    }

    @Override
    public boolean updateUserByUsername(User user) {
        User updateUser = new User();
        updateUser.setUsername(user.getUsername());
        updateUser.setDeleted("N");
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        wrapper.eq("username", updateUser.getUsername());
        return this.update(updateUser, wrapper);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean update(User user) {
        if (StringUtils.isNotBlank(user.getPassword())) {
//            user.setPassword(passwordEncoder.encode(user.getPassword()));
            user.setPassword(user.getPassword());
        }
        boolean isSuccess = this.updateById(user);
        userRoleService.saveBatch(user.getId(), user.getRoleIds());
        return isSuccess;
    }

    @Override
    public UserVo get(String id) {
        User user = this.getById(id);
        if (Objects.isNull(user)) {
            throw new UserNotFoundException("user not found with id:" + id);
        }
        user.setRoleIds(userRoleService.queryByUserId(id));
        if (CollectionUtils.isNotEmpty(user.getRoleIds())) {
            String roleId = user.getRoleIds().iterator().next();
            if (StringUtils.isNotBlank(roleId)) {
                Role role = roleService.get(roleId);
                user.setRoleCode(role.getCode());
                user.setRoleName(role.getName());
            }
        }
        return new UserVo(user);
    }

    @Override
    public User getByUniqueId(String uniqueId) {
        User user = this.getOne(new QueryWrapper<User>()
                .eq("username", uniqueId));
//                .or()
//                .eq("mobile", uniqueId));
        if (Objects.isNull(user)) {
            throw new UserNotFoundException("user not found with uniqueId:" + uniqueId);
        }
        user.setRoleIds(userRoleService.queryByUserId(user.getId()));
        return user;
    }

    @Override
    public IPage<UserVo> query(Page page, UserQueryParam userQueryParam) {
        QueryWrapper<User> queryWrapper = userQueryParam.build();
        queryWrapper.eq(StringUtils.isNotBlank(userQueryParam.getName()), "name", userQueryParam.getName());
        queryWrapper.eq(StringUtils.isNotBlank(userQueryParam.getUsername()), "username", userQueryParam.getUsername());
//        queryWrapper.eq(StringUtils.isNotBlank(userQueryParam.getMobile()), "mobile", userQueryParam.getMobile());
        // 转换成 VO
        IPage<User> iPageUser = this.page(page, queryWrapper);
        if (iPageUser.getRecords() != null) {
            iPageUser.getRecords().forEach(user -> user.setRoleIds(userRoleService.queryByUserId(user.getId())));
        }
        return iPageUser.convert(UserVo::new);
    }

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        //根据用户名获取用户
        User user = getByUniqueId(username);
        if (user != null) {
            //获取用户的所有权限
            List<Role> permissionList = roleService.query(user.getId());
            //返回自己实现的用户用户信息
            return new CustomerUserDetails(user, permissionList);
        }
        throw new UsernameNotFoundException("用户名或密码错误");
    }

    @Override
    public User getByUserId(String userId) {
        User user = this.getOne(new QueryWrapper<User>().eq("id", userId));
        if (Objects.isNull(user)) {
            throw new UserNotFoundException("user not found with userId:" + userId);
        }
        user.setRoleIds(userRoleService.queryByUserId(user.getId()));
        return user;
    }

    @Override
    public List<User> all() {
        List<User> allUserList = this.list();
        allUserList.forEach(user -> {
            user.setPassword("");
            user.setSeatNames(seatService.getSeatNamesByUsername(user.getUsername()));
        });
        return allUserList;
    }

    @Override
    public boolean addSeatsToUserBySeatIds(String id, Set<String> seatIds) {
        this.getBaseMapper().deleteUSRByUserId(id);
        seatIds.forEach(seatId -> this.getBaseMapper().insertToUSR(id, seatId));
        return true;
    }

    @Override
    public Set<Module> getModulesByUsername(String username) {
        return this.getBaseMapper().getModulesByUsername(username);
    }

    @Override
    public Set<String> getSeatIpsByUsername(String username) {
        return this.getBaseMapper().getSeatIpsByUsername(username);
    }
}
